package ar.com.santiagobasulto.crawler.core;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;

import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;


public class URLProcessorWrapper implements Runnable {

	private Class<? extends URLProcessor> processorClass;

	private BlockingQueue<URL> notProcessedURLs;
	private Set<URL> processedURLs;

	private ExecutorService pool;
	public URLProcessorWrapper(BlockingQueue<URL> notProcessedURLs,Set<URL> processedURLs, Class<? extends URLProcessor> processorClass,ExecutorService pool) {
		this.processorClass = processorClass;
		this.notProcessedURLs = notProcessedURLs;
		this.processedURLs = processedURLs;
		this.pool = pool;
	}

	/**
	 * Warning!
	 * This method hangs. There is no stop criteria.
	 */
	@Override
	public void run() {
		try {
			boolean done = false;
			while(!done){
				URL url = notProcessedURLs.poll(TIME_TO_WAIT_WHILE_POLLING, TIME_UNIT);
				if(url==null){
                    //There's no more URLs, should i finish?
                    done=true;
				}else{
					boolean proceed = false;
					synchronized (processedURLs) {
						if(!processedURLs.contains(url)){
							proceed = true;
							processedURLs.add(url);
						}
					}
					if(proceed){
						//new processor instance
						URLProcessor urlProcessor = createProcessor(url);
						if(urlProcessor!=null)
							pool.submit(urlProcessor);
						//process
					}
				}
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
	private URLProcessor createProcessor(URL startingURL){
		Constructor<? extends URLProcessor> c;
		try {
			c = this.processorClass.getConstructor(URL.class);
			URLProcessor newInstance = c.newInstance(startingURL);
			return newInstance;
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	public static void setTimeToWait(long time,TimeUnit timeUnit){
    	TIME_TO_WAIT_WHILE_POLLING = time;
    	TIME_UNIT = timeUnit;
    }
    private static long TIME_TO_WAIT_WHILE_POLLING = 3;
    private static TimeUnit TIME_UNIT = TimeUnit.SECONDS;
}
